/******************************************************************************
This file is part of AppKit.
Project: appkit
Author : FergusZeng
Email  : cblock@126.com
git	   : https://gitee.com/newgolo/appkit.git
*******************************************************************************
MIT License

Copyright (c) 2022 cblock@126.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#pragma once

#include <map>
#include <memory>

#include "appkit/basetype.h"
#include "appkit/datetime.h"
#include "appkit/fileio.h"
#include "appkit/thread.h"

/**
 * @file  timer.h
 * @brief 定时器
 */
namespace appkit {

/**
 * @class Timer
 * @brief 定时器类(低精度定时器)
 * @note 已知BUG:长时间运行有概率出现定时器停止的问题(原因暂时未知!!!)
 */
class Timer {
    DECL_CLASSMETA(Timer)

public:
    using Ptr = std::shared_ptr<Timer>;

public:
    /**
     * @brief 构造定时器
     * @param milliseconds 毫秒,必须大于0
     * @param repeated
     * @note 在构造函数中会调用reset()进行复位
     */
    explicit Timer(int milliseconds, bool repeated = false);
    ~Timer();

private:
    /**
     * @brief 检查是否到期
     * @param callback 定时回调函数
     * @note 定时器的起始时间为调用reset()的时间点
     */
    bool checkTimeout(std::function<void()> callback = nullptr);
    /**
     * @brief 重置定时器
     * @param milliseconds 当milliseconds<=0时,不复位超时时间和重复方式
     * @param repeated 重复方式
     */
    void reset(int milliseconds = 0, bool repeated = false);

private:
    friend class TimerManager;
    Time m_startTime;
    bool m_isRepeated{false};
    int m_usInterval{0};
    bool m_expired{false};
};

/**
 * @class TimerManager
 * @brief 定时器管理器
 */
class TimerManager : public Runnable {
    DECL_CLASSMETA(TimerManager)

public:
    TimerManager();
    ~TimerManager();
    /**
     * @brief 注册定时器
     * @param timer 定时器
     * @param callback 定时回调
     * @return true
     * @return false
     */
    bool registerTimer(const Timer& timer, std::function<void()> callback);
    /**
     * @brief 注销定时器
     * @param timer
     * @return true
     * @return false
     */
    bool unregisterTimer(const Timer& timer);
    /**
     * @brief 启动定时
     * @return true
     * @return false
     */
    bool start();
    /**
     * @brief 停止定时
     */
    void stop();

private:
    void run(const Thread& thread);

private:
    std::mutex m_mutex;
    Thread m_thread{"TimerManager"};
    std::map<Timer*, std::function<void()>> m_timerMap;
};

/**
 * @class TimerListener
 * @brief Timer定时器监听器接口
 */
class TimerListener {
public:
    TimerListener() {}
    virtual ~TimerListener() {}
    /**
     * @brief 定时回调函数
     * @param timerID
     * @note
     * 回调函数中不允许调用任何影响Timer生命周期的方法,比如start(),stop()等
     */
    virtual void onTimer(int timerID) = 0;
};

/**
 *  @class  RTimer
 *  @brief  实时定时器类(较高精度,适用于毫秒级定时)
 */
class RTimer : public Runnable {
    DECL_CLASSMETA(RTimer)
    using Ptr = std::shared_ptr<RTimer>;

public:
    /**
     * @brief RTimer构造函数
     * @param listener 定时器监听器
     * @param timerID 定时器ID
     */
    RTimer(const TimerListener& listener, int timerID);
    ~RTimer();
    /**
     * @brief 启动定时器
     * @param msTimeout 定时时间(unit: ms)
     * @param repeated 是否重复
     * @return true 启动成功
     * @return false 启动失败
     */
    bool start(int msTimeout, bool repeated = false);
    /**
     * @brief 停止定时器
     */
    void stop();
    /**
     * @brief 获取定时器ID
     * @return int 定时器ID
     */
    int id() { return m_timerID; }

private:
    void run(const Thread& thread);

private:
    std::unique_ptr<Thread> m_thread{nullptr};
    TimerListener* m_listener{nullptr};
    bool m_isRepeated{false};
    int m_timerID{0};
    int m_usInterval{0};
    int m_usTick{1};
};

/**
 *  @class  HRTimer
 *  @brief  高精度定时器(基于事件实现的定时器类,适用于实时系统中微秒级定时)
 */
class HRTimer : public Runnable {
    DECL_CLASSMETA(HRTimer)

public:
    /**
     * @brief PollTimer构造函数
     * @param listener 定时器监听器
     * @param timerID 定时器ID
     */
    HRTimer(const TimerListener& listener, int timerID);
    ~HRTimer();
    /**
     * @brief 启动定时器
     * @param usTimeout 定时时间
     * @param repeated 是否重复
     * @return true 启动成功
     * @return false 启动失败
     */
    bool start(int usTimeout, bool repeated = false);
    /**
     * @brief 停止定时器
     */
    void stop();
    /**
     * @brief 获取定时器ID
     * @return int 定时器ID
     */
    int id() { return m_timerID; }

private:
    void run(const Thread& thread);

private:
    Thread m_thread{"HRTimer"};
    TimerListener* m_listener{nullptr};
    Poller m_poller;
    int m_tmfd{-1};
    int m_usInterval{0};
    int m_timerID{0};
};
}  // namespace appkit
